import LogIndexedDB  from './LogIndexedDB';
/**
 * WebSocket 事件类型
 */
type WebSocketEventType = 'open' | 'close' | 'message' | 'error' | 'reconnect' | 'reconnectFailed';
/**
 * WebSocket 事件监听器
 */
type WebSocketEventListener = (data?: any) => void;
/**
 * WebSocket 配置选项
 */
interface WebSocketOptions {
  url: string;
  heartbeatInterval?: number;
  heartbeatMessage?: string | object;
  reconnectInterval?: number;
  maxReconnectAttempts?: number;
}
/**
 * WebSocket 单例类
 * 使用发布订阅模式处理事件
 */
const logDB = LogIndexedDB.getInstance()
class WebSocketClient {
  /** 单例实例 */
  private static instance: WebSocketClient | null = null;
  /** WebSocket 实例 */
  private ws: WebSocket | null = null;
  /** WebSocket 连接地址 */
  private readonly url: string;
  /** 重连计数器 */
  private reconnectCount: number = 0;
  /** 最大重连尝试次数 */
  private readonly maxReconnectAttempts: number;
  /** 重连间隔时间(毫秒) */
  private readonly reconnectInterval: number;
  /** 心跳检测间隔时间(毫秒) */
  private readonly heartbeatInterval: number;
  /** 心跳消息内容 */
  private readonly heartbeatMessage: string;
  /** 心跳定时器 */
  private heartbeatTimer: number | null = null;
  /** 重连定时器 */
  private reconnectTimer: number | null = null;
  /** 事件监听器集合 */
  private listeners: Record<string, WebSocketEventListener[]> = {};
  /** 连接状态 */
  private connected: boolean = false;
  /** 是否主动关闭 */
  private isClose: boolean = false;
  /** 待发送消息队列 */
  private messageQueue: (string | object)[] = [];

  private constructor(options: WebSocketOptions) {
    this.url = options.url;
    this.heartbeatInterval = options.heartbeatInterval || 30000;
    this.heartbeatMessage = typeof options.heartbeatMessage === 'string' 
      ? options.heartbeatMessage 
      : JSON.stringify(options.heartbeatMessage || { commands: 'heartbeat', data: 'ping' });
    this.reconnectInterval = options.reconnectInterval || 3000;
    this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
    this.connect();
  }

  /**
   * 获取 WebSocket 单例实例
   */
  public static getInstance(options: WebSocketOptions): WebSocketClient {
    if (!WebSocketClient.instance) {
      WebSocketClient.instance = new WebSocketClient(options);
    } else if (options.url && options.url !== WebSocketClient.instance.url) {
      WebSocketClient.instance.close();
      WebSocketClient.instance = new WebSocketClient(options);
    }
    return WebSocketClient.instance;
  }

  /**
   * 建立 WebSocket 连接
   */
  private async connect(): Promise<void> {
    await logDB.init()
    await logDB.clearAllLogs()
    if (this.ws) {
      this.ws.close();
    }
    try {
      // 连接时添加时间戳,确保连接的唯一性
      this.ws = new WebSocket(this.url + `?timestamp=${Date.now()}`);      
      this.ws.onopen = async () => {
        console.log("WebSocket 连接已建立");
        this.connected = true;
        this.reconnectCount = 0;
        this.startHeartbeat();
        this.sendQueuedMessages();
        this.emit('open');
      };   
      this.ws.onmessage = (event: MessageEvent) => {
        try {
          const data = JSON.parse(event.data);
          if (data.cmd === 'heartbeat') {
            return;
          }
          this.emit('message', data);
        } catch (error) {
          console.error('解析消息失败:', error);
          this.emit('message', event.data);
        }
      };
      
      this.ws.onclose = () => {
        console.log('WebSocket 连接已关闭');
        this.connected = false;
        this.stopHeartbeat();
        this.emit('close');
        if(this.isClose){
          this.listeners = {}
          WebSocketClient.instance = null
          return
        }
        this.reconnect();
      };
      
      this.ws.onerror = (error: Event) => {
        console.error('WebSocket 连接发生错误:', error);
        this.connected = false;
        this.emit('error', error);
      };
    } catch (error) {
      console.error('WebSocket 连接创建失败:', error);
      this.reconnect();
    }
  }

  /**
   * 重新连接
   */
  private reconnect(): void {
    if (this.isClose) return;
    
    if (this.reconnectCount >= this.maxReconnectAttempts) {
      console.log(`WebSocket 重连失败，已达到最大重连次数: ${this.maxReconnectAttempts}`);
      this.emit('reconnectFailed');
      return;
    }
    
    if (this.reconnectTimer) {
      window.clearTimeout(this.reconnectTimer);
    }
    
    this.reconnectTimer = window.setTimeout(async () => {
      console.log(`WebSocket 正在尝试第 ${this.reconnectCount + 1} 次重连...`);
      this.reconnectCount++;
      this.emit('reconnect', this.reconnectCount);
      this.connect();
    }, this.reconnectInterval);
  }

  /**
   * 开始心跳检测
   */
  private startHeartbeat(): void {
    this.stopHeartbeat();
    
    this.heartbeatTimer = window.setInterval(() => {
      if (this.connected) {
        this.send(this.heartbeatMessage);
      }
    }, this.heartbeatInterval);
  }

  /**
   * 停止心跳检测
   */
  private stopHeartbeat(): void {
    if (this.heartbeatTimer) {
      window.clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  /**
   * 发送队列中的消息
   */
  private sendQueuedMessages(): void {
    while (this.messageQueue.length > 0) {
      const message = this.messageQueue.shift();
      if (message) {
        this.sendMessage(message);
      }
    }
  }

  /**
   * 实际发送消息的内部方法
   */
  private sendMessage(data: string | object): boolean {
    try {
      const message = typeof data === 'string' ? data : JSON.stringify(data);
      this.ws?.send(message);
      return true;
    } catch (error) {
      console.error('发送消息失败:', error);
      return false;
    }
  }

  /**
   * 发送消息
   */
  public send(data: string | object): boolean {
    if (!this.connected) {
      console.warn('WebSocket 未连接，消息将加入队列等待连接建立');
      this.messageQueue.push(data);
      return false;
    }

    return this.sendMessage(data);
  }

  /**
   * 关闭连接
   */
  public close(): void {
    this.isClose = true
    this.stopHeartbeat();  
    if (this.reconnectTimer) {
      window.clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
    this.connected = false;
  }

  /**
   * 订阅事件
   */
  public on(event: WebSocketEventType, callback: WebSocketEventListener): void {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event].push(callback);
  }

  /**
   * 取消订阅事件
   */
  public off(event: WebSocketEventType, callback?: WebSocketEventListener): void {
    if (!this.listeners[event]) {
      return;
    }
    
    if (!callback) {
      delete this.listeners[event];
      return;
    }
    
    this.listeners[event] = this.listeners[event].filter(
      listener => listener !== callback
    );
  }

  /**
   * 触发事件
   */
  private emit(event: WebSocketEventType, data?: any): void {
    if (!this.listeners[event]) {
      return;
    }
    
    this.listeners[event].forEach(callback => {
      try {
        callback(data);
      } catch (error) {
        console.error(`执行 ${event} 事件回调时发生错误:`, error);
      }
    });
  }

  /**
   * 获取连接状态
   */
  public isConnected(): boolean {
    return this.connected;
  }
}

export default WebSocketClient; 